<template>
    <div class="container">
        <input type="file" accept="image/*" @change="handleFileUpload" />

        <div v-if="imgSrc" class="preview-wrapper">
            <div class="preview-container" ref="previewContainer">
                <img ref="previewImage" :src="imgSrc" @load="initCropBox" />
                <div
                    v-show="showCropBox"
                    class="crop-box"
                    :style="cropBoxStyle"
                    @pointerdown.prevent="startInteraction('move')"
                    @touchstart.prevent
                >
                    <div
                        class="crop-handle top-left"
                        @pointerdown.stop="startInteraction('resize', 'tl')"
                        @touchstart.stop
                    ></div>
                    <div
                        class="crop-handle top-right"
                        @pointerdown.stop="startInteraction('resize', 'tr')"
                        @touchstart.stop
                    ></div>
                    <div
                        class="crop-handle bottom-left"
                        @pointerdown.stop="startInteraction('resize', 'bl')"
                        @touchstart.stop
                    ></div>
                    <div
                        class="crop-handle bottom-right"
                        @pointerdown.stop="startInteraction('resize', 'br')"
                        @touchstart.stop
                    ></div>
                </div>
            </div>

            <div class="controls">
                <button @pointerdown="cropImage" @touchstart.stop>
                    {{ $fn.lg('asai.confirm') }}
                </button>
                <button
                    @pointerdown="downloadImage"
                    @touchstart.stop
                    v-if="croppedImage"
                >
                    {{ $fn.lg('asai.download') }}
                </button>
                <button
                    @pointerdown="uploadImage"
                    @touchstart.stop
                    v-if="croppedImage"
                >
                    {{ $fn.lg('asai.upload') }}
                </button>
            </div>

            <div v-if="croppedImage" class="result-preview">
                <img :src="croppedImage" />
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';
const props: any = defineProps<{
    ujt: any;
    modelValue: any;
}>();
const { $fn, $global } = props.ujt;
// 处理双向绑定的值，v-model
const emit = defineEmits(['update:modelValue']);
const cmModelValue = computed({
    get() {
        return props.modelValue;
    },
    set(val: string) {
        emit('update:modelValue', val);
    },
});

const imgSrc = ref('');
const croppedImage = ref('');
const previewImage = ref(null);
const previewContainer = ref(null);

// 裁剪框参数
const cropParams = ref({
    x: 0,
    y: 0,
    width: 0,
    height: 0,
    maxWidth: 0,
    maxHeight: 0,
});

// 交互状态
const interaction = ref({
    type: null,
    startX: 0,
    startY: 0,
    originalX: 0,
    originalY: 0,
    originalWidth: 0,
    originalHeight: 0,
    direction: null,
});

// 计算裁剪框样式
const cropBoxStyle = computed(() => {
    return {
        transform: `translate(${cropParams.value.x}px, ${cropParams.value.y}px)`,
        width: `${cropParams.value.width}px`,
        height: `${cropParams.value.height}px`,
    };
});

const showCropBox = computed(
    () => cropParams.value.width > 0 && cropParams.value.height > 0
);

// 处理文件上传
const handleFileUpload = (e) => {
    const file = e.target.files[0];
    if (!file) return;

    const reader = new FileReader();
    reader.onload = (e) => {
        imgSrc.value = e.target.result;
        croppedImage.value = '';
    };
    reader.readAsDataURL(file);
};

// 初始化裁剪框
const initCropBox = () => {
    const img = previewImage.value;
    const container = previewContainer.value;
    if (!img || !container) {
        return;
    }
    const maxWidth = Math.min(container.clientWidth, img.naturalWidth);
    const maxHeight = Math.min(container.clientHeight, img.naturalHeight);

    const initWidth = Math.min(maxWidth * 0.8, img.naturalWidth);
    const initHeight = Math.min(maxHeight * 0.8, img.naturalHeight);

    cropParams.value = {
        x: (maxWidth - initWidth) / 2,
        y: (maxHeight - initHeight) / 2,
        width: initWidth,
        height: initHeight,
        maxWidth,
        maxHeight,
    };
};

// 开始交互
const startInteraction = (type, direction = null) => {
    const event = window.event || event;
    const touch = event.touches ? event.touches[0] : event;
    interaction.value = {
        type,
        startX: touch.clientX,
        startY: touch.clientY,
        originalX: cropParams.value.x,
        originalY: cropParams.value.y,
        originalWidth: cropParams.value.width,
        originalHeight: cropParams.value.height,
        direction,
    };

    const moveHandler = (e) => {
        requestAnimationFrame(() => {
            if (type === 'move') {
                handleMove(e);
            } else {
                handleResize(e);
            }
        });
    };

    window.addEventListener('mousemove', moveHandler);
    window.addEventListener('touchmove', moveHandler);
    window.addEventListener('mouseup', stopInteraction);
    window.addEventListener('touchend', stopInteraction);
};

// 处理移动
const handleMove = (e) => {
    const event = window.event || e;
    const touch = event.touches ? event.touches[0] : event;
    if (interaction.value.type !== 'move') return;

    const dx = touch.clientX - interaction.value.startX;
    const dy = touch.clientY - interaction.value.startY;

    const newX = Math.max(
        0,
        Math.min(
            interaction.value.originalX + dx,
            cropParams.value.maxWidth - cropParams.value.width
        )
    );

    const newY = Math.max(
        0,
        Math.min(
            interaction.value.originalY + dy,
            cropParams.value.maxHeight - cropParams.value.height
        )
    );

    Object.assign(cropParams.value, { x: newX, y: newY });
};

// 处理调整大小
const handleResize = (e) => {
    const event = window.event || e;
    const touch = event.touches ? event.touches[0] : event;
    if (interaction.value.type !== 'resize') return;

    const dx = touch.clientX - interaction.value.startX;
    const dy = touch.clientY - interaction.value.startY;
    const direction = interaction.value.direction;

    let newWidth = interaction.value.originalWidth;
    let newHeight = interaction.value.originalHeight;
    let newX = interaction.value.originalX;
    let newY = interaction.value.originalY;

    switch (direction) {
        case 'tr':
            newWidth = Math.max(
                100,
                Math.min(
                    interaction.value.originalWidth + dx,
                    cropParams.value.maxWidth - newX
                )
            );
            newHeight = Math.max(100, interaction.value.originalHeight - dy);
            newY = Math.max(0, interaction.value.originalY + dy);
            break;
        case 'tl':
            newWidth = Math.max(100, interaction.value.originalWidth - dx);
            newHeight = Math.max(100, interaction.value.originalHeight - dy);
            newX = Math.max(0, interaction.value.originalX + dx);
            newY = Math.max(0, interaction.value.originalY + dy);
            break;
        case 'br':
            newWidth = Math.max(100, interaction.value.originalWidth + dx);
            newHeight = Math.max(100, interaction.value.originalHeight + dy);
            break;
        case 'bl':
            newWidth = Math.max(100, interaction.value.originalWidth - dx);
            newHeight = Math.max(100, interaction.value.originalHeight + dy);
            newX = Math.max(0, interaction.value.originalX + dx);
            break;
    }

    // 确保裁剪框不超出图片边界
    newWidth = Math.min(newWidth, cropParams.value.maxWidth - newX);
    newHeight = Math.min(newHeight, cropParams.value.maxHeight - newY);

    Object.assign(cropParams.value, {
        x: newX,
        y: newY,
        width: newWidth,
        height: newHeight,
    });
};

// 停止交互
const stopInteraction = () => {
    interaction.value.type = null;
    window.removeEventListener('mousemove', handleMove);
    window.removeEventListener('touchmove', handleMove);
    window.removeEventListener('mousemove', handleResize);
    window.removeEventListener('touchmove', handleResize);
    window.removeEventListener('mouseup', stopInteraction);
    window.removeEventListener('touchend', stopInteraction);
};

// 执行裁剪
const cropImage = () => {
    const img: any = previewImage.value;
    const scaleX = img.naturalWidth / img.width;
    const scaleY = img.naturalHeight / img.height;

    const canvasWidth = Math.min(
        cropParams.value.width * scaleX,
        img.naturalWidth
    );
    const canvasHeight = Math.min(
        cropParams.value.height * scaleY,
        img.naturalHeight
    );

    const canvas = document.createElement('canvas');
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    const ctx = canvas.getContext('2d');
    ctx.drawImage(
        img,
        cropParams.value.x * scaleX,
        cropParams.value.y * scaleY,
        canvasWidth,
        canvasHeight,
        0,
        0,
        canvasWidth,
        canvasHeight
    );

    croppedImage.value = canvas.toDataURL('image/png', 0.9);
};

// 下载图片
const downloadImage = () => {
    const link = document.createElement('a');
    link.download = 'cropped-image.png';
    link.href = croppedImage.value;
    link.click();
};
// 上传图片
const uploadImage = () => {
    // cmModelValue.value = croppedImage.value;

    const base64Data = croppedImage.value.split(',')[1];
    const upid = $fn.As.Uuid();
    $fn.api['webserver']
        .apiPost(
            '/api/asaifile/manage/upbase64/?path=' +
                $global.sys.path.updir +
                upid +
                '.png',
            base64Data
        )
        .then((res: any) => {
            cmModelValue.value = res.data;
        });
};
</script>

<style scoped>
.container {
    padding: 20px;
    max-width: 800px;
    margin: 0 auto;
}

.preview-wrapper {
    margin-top: 20px;
}

.preview-container {
    position: relative;
    overflow: hidden;
    background: #f0f0f0;
    max-height: 70vh;
}

.preview-container img {
    display: block;
    max-width: 100%;
    max-height: 70vh;
    object-fit: contain;
}

.crop-box {
    position: absolute;
    top: 0;
    left: 0;
    border: 2px solid #fff;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
    cursor: move;
}

.crop-handle {
    position: absolute;
    width: 12px;
    height: 12px;
    background: #fff;
    border: 2px solid #409eff;
    border-radius: 50%;
}

.top-left {
    left: -6px;
    top: -6px;
    cursor: nwse-resize;
}
.top-right {
    right: -6px;
    top: -6px;
    cursor: nesw-resize;
}
.bottom-left {
    left: -6px;
    bottom: -6px;
    cursor: nesw-resize;
}
.bottom-right {
    right: -6px;
    bottom: -6px;
    cursor: nwse-resize;
}

.controls {
    margin: 20px 0;
    display: flex;
    gap: 10px;
}

button {
    padding: 8px 16px;
    background: #409eff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
}

button:hover {
    background: #66b1ff;
}

.result-preview {
    margin-top: 20px;
}

.result-preview img {
    max-width: 100%;
    border: 1px solid #ddd;
}
</style>
